﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BacteriaSimulation.Simulation
{
    public class DuplicateBacteriumTask : AbstractTask
    {
        public override TaskOutcome executeTask(Simulation simulation, Bacterium bacterium, SimulationEnvironment env)
        {
            if (bacterium.Energy >= bacterium.MaxEnergy)
            {
                // the Bacterium is dying
                bacterium.State = BacteriumState.DEAD;
                // add the bacterium to the list of the bacteria that will be removed
                simulation.RemovingBacteria.Add(bacterium);

                // duplicates the dying bacterium

                // Duplicates the bacterium
                Double leftXRand = simulation.Random.NextDouble();
                Double leftYRand = simulation.Random.NextDouble();
                Double rightXRand = simulation.Random.NextDouble();
                Double rightYRand = simulation.Random.NextDouble();
                Double energySplitFactor = simulation.Random.NextDouble();
                Double energySplitFactorCompl = 1 - energySplitFactor;

                Vector2D leftDirection = new Vector2D(Math.Sign(bacterium.Speed.XComponent) * leftXRand,
                    Math.Sign(bacterium.Speed.YComponent) * leftYRand);
                Vector2D rightDirection = new Vector2D(Math.Sign(bacterium.Speed.XComponent) * rightXRand,
                    Math.Sign(bacterium.Speed.YComponent) * rightYRand);

                //Randomly determines if there is a mutation (for now, a mutation simply implies that the speed module of
                // the generated bacteria is different than the original one)
                Double speedModule = bacterium.SpeedMagnitude;
                Double energyIncrement = bacterium.EnergyIncrement;
                Double guess = simulation.Random.NextDouble();
                Boolean mutation = guess < env.MutationProbability;
                if (mutation)
                {
                    // the speed of the duplicated bacteria can be either higher or lower than the original one
                    Double speedIncrement = simulation.Random.NextDouble();
                    Int32 sign = simulation.Random.Next(3) == 1 ? 1 : -1;
                    if ((sign * speedIncrement < 0 && Math.Abs(speedIncrement) < speedModule)
                        || speedIncrement > 0)
                    {
                        speedModule += sign * speedIncrement;
                    }
                    //if ((speedIncrement < 0 && Math.Abs(speedIncrement) < energyIncrement)
                    //    || speedIncrement > 0)
                    //{
                    //    energyIncrement += Math.Sqrt(speedIncrement / Math.PI);
                    //}
                }

                Bacterium leftBacterium = new Bacterium(simulation, bacterium.Position.Clone(), leftDirection, speedModule, bacterium.AccelerationMagnitude,
                    bacterium.Energy * energySplitFactor, bacterium.Strategy, bacterium.MaxEnergy, bacterium.MaxSpeedMagnitude, energyIncrement);

                SimulationPoint rightPosition = bacterium.Position.Clone();
                rightPosition.X += leftBacterium.Position.X + leftBacterium.Width + env.Epsilon;
                rightPosition.Y += leftBacterium.Position.Y + leftBacterium.Height + env.Epsilon;
                Bacterium rightBacterium = new Bacterium(simulation, bacterium.Position.Clone(), rightDirection, speedModule, bacterium.AccelerationMagnitude,
                    bacterium.Energy * energySplitFactorCompl, bacterium.Strategy, bacterium.MaxEnergy, bacterium.MaxSpeedMagnitude, energyIncrement);
                rightBacterium.Brother = leftBacterium;
                leftBacterium.Brother = rightBacterium;

                simulation.AddingBacteria.Add(leftBacterium);
                simulation.AddingBacteria.Add(rightBacterium);

                return new TaskOutcome(TaskOutcomeType.END_CHAIN);
            }

            return new TaskOutcome(TaskOutcomeType.CONTINUE);
        }
    }
}
